package drds.server.net.packet;

import java.nio.ByteBuffer;

import drds.server.Server;
import drds.server.net.SessionContext$LifeCycle;

/**
 * From server to client in response to command, if no error and no result set.
 * 
 * <pre>
 * Bytes                       Name
 * -----                       ----
 * 1                           field_count, always = 0
 * 1-9 (Length Coded Binary)   affected_rows
 * 1-9 (Length Coded Binary)   insert_id
 * 2                           server_status
 * 2                           warning_count
 * n   (until end of packet)   message fix:(Length Coded String)
 * 
 * @see http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#OK_Packet
 * </pre>
 * 
 * @author 曹正辉<330937205@qq.com>
 * 
 */
public class OkPacket extends Packet {
	public static final byte FIELD_COUNT = 0x00;
	public static final byte[] OK = new byte[] { 7, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0 };

	public byte fieldCount = FIELD_COUNT;
	public long affectedRowCount;
	public long insertId;
	public int serverStatus;
	public byte[] message;

	public void read(BinaryPacket binaryPacket) {
		packetLength = binaryPacket.packetLength;
		packetId = binaryPacket.packetId;
		BytesHolder bytesHolder = new BytesHolder(binaryPacket.bytes);
		fieldCount = bytesHolder.read();
		affectedRowCount = bytesHolder.readLength();
		insertId = bytesHolder.readLength();
		serverStatus = bytesHolder.readInt2();
		if (bytesHolder.hasRemaining()) {
			this.message = bytesHolder.readBytesWithLength();
		}
	}

	public void read(byte[] bytes) {
		BytesHolder BytesHolder = new BytesHolder(bytes);
		packetLength = BytesHolder.readInt3();
		packetId = BytesHolder.read();
		fieldCount = BytesHolder.read();
		affectedRowCount = BytesHolder.readLength();
		insertId = BytesHolder.readLength();
		serverStatus = BytesHolder.readInt2();
		if (BytesHolder.hasRemaining()) {
			this.message = BytesHolder.readBytesWithLength();
		}
	}

	public byte[] writeToBytes(SessionContext$LifeCycle sessionContext) {
		ByteBuffer byteBuffer = sessionContext.allocate();
		this.write(byteBuffer, sessionContext);
		byteBuffer.flip();
		byte[] bytes = new byte[byteBuffer.limit()];
		byteBuffer.get(bytes);
		sessionContext.recycle(byteBuffer);
		return bytes;
	}

	private ByteBuffer write(ByteBuffer byteBuffer, SessionContext$LifeCycle sessionContext) {

		int size = computePacketSize();
		byteBuffer = sessionContext.checkWriteByteBuffer(byteBuffer, sessionContext.getPacketHeaderSize() + size, true);
		ByteBufferUtil.writeInt3(byteBuffer, computePacketSize());
		byteBuffer.put(packetId);
		byteBuffer.put(fieldCount);
		ByteBufferUtil.writeLength(byteBuffer, affectedRowCount);
		ByteBufferUtil.writeLength(byteBuffer, insertId);
		ByteBufferUtil.writeInt2(byteBuffer, serverStatus);
		if (message != null) {
			ByteBufferUtil.writeWithLength(byteBuffer, message);
		}

		return byteBuffer;

	}

	public void write(SessionContext$LifeCycle sessionContext) {
		ByteBuffer byteBuffer = write(sessionContext.allocate(), sessionContext);
		sessionContext.write(byteBuffer);
	}

	@Override
	public int computePacketSize() {
		int i = 1;
		i += ByteBufferUtil.getLength(affectedRowCount);
		i += ByteBufferUtil.getLength(insertId);
		i += 4;
		if (message != null) {
			i += ByteBufferUtil.getLength(message);
		}
		return i;
	}

	public byte[] writeToBytes() {

		int totalSize = computePacketSize() + packetHeaderSize;
		ByteBuffer byteBuffer = Server.getInstance().getByteBufferPool().allocate(totalSize);
		ByteBufferUtil.writeInt3(byteBuffer, computePacketSize());
		byteBuffer.put(packetId);
		byteBuffer.put(fieldCount);
		ByteBufferUtil.writeLength(byteBuffer, affectedRowCount);
		ByteBufferUtil.writeLength(byteBuffer, insertId);
		ByteBufferUtil.writeInt2(byteBuffer, serverStatus);
		if (message != null) {
			ByteBufferUtil.writeWithLength(byteBuffer, message);
		}
		byteBuffer.flip();
		byte[] bytes = new byte[byteBuffer.limit()];
		byteBuffer.get(bytes);
		Server.getInstance().getByteBufferPool().recycle(byteBuffer);
		return bytes;
	}

}